using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace SPGE
{
    public class SimpleTransition : TransitionScene
    {
        static BasicEffect be;

        static VertexPositionTexture[] vertices = new VertexPositionTexture[4];
        static short[] indices = new short[4];
        static VertexBuffer vb;
        static IndexBuffer ib;

        bool renderedOnce;

        public SimpleTransition(IScene outgoing, IScene incomming, TimeSpan dur)
            : base(outgoing, incomming, dur)
        {
            if (GameContainer.CurrentContainer.GraphicsDevice != null)
                CreateRenderTargetMethods();
            else
            {
                
                GameContainer.CurrentContainer.DeviceManager.DeviceCreated += new EventHandler<EventArgs>(OnDeviceCreated);
            }
        }

        void OnDeviceCreated(object sender, EventArgs e)
        {
            CreateRenderTargetMethods();
        }

        private static void CreateRenderTargetMethods()
        {
            if(InRT == null || InRT.IsDisposed)
                InRT = new RenderTarget2D(GameContainer.Device, GameContainer.Device.DisplayMode.Width, GameContainer.Device.DisplayMode.Height, false, SurfaceFormat.Color, DepthFormat.Depth16, 4, RenderTargetUsage.DiscardContents);
            if (OutRT == null || OutRT.IsDisposed)
                OutRT = new RenderTarget2D(GameContainer.Device, GameContainer.Device.DisplayMode.Width, GameContainer.Device.DisplayMode.Height, false, SurfaceFormat.Color, DepthFormat.Depth16, 0, RenderTargetUsage.DiscardContents);

            if (be == null || be.IsDisposed)
                be = new BasicEffect(GameContainer.Device);

            if (vb == null || vb.IsDisposed)
                vb = new VertexBuffer(GameContainer.Device, typeof(VertexPositionColorTexture), 4, BufferUsage.WriteOnly);
            if (ib == null || ib.IsDisposed)
                ib = new IndexBuffer(GameContainer.Device, typeof(ushort), 4, BufferUsage.WriteOnly);

            vertices[0] = new VertexPositionTexture(Vector3.Zero, Vector2.UnitY);
            vertices[1] = new VertexPositionTexture(new Vector3(0, 800, 0), Vector2.Zero);
            vertices[2] = new VertexPositionTexture(new Vector3(480, 0, 0), Vector2.One);
            vertices[3] = new VertexPositionTexture(new Vector3(480, 800, 0), Vector2.UnitX);

            indices = new short[4] { 0, 1, 2, 3 };

            ib.SetData(indices);
            vb.SetData<VertexPositionTexture>(vertices);

            be.TextureEnabled = true;

            be.View = Matrix.CreateLookAt(new Vector3(0, 0, 1000), Vector3.Zero, Vector3.UnitY);
            be.Projection = Matrix.CreatePerspective(48, 80, 100, 2000);
        }

        public override void Load(ResourceGroupHandler gm)
        {
        }

        public override void Draw(Microsoft.Xna.Framework.GameTime gameTime, Microsoft.Xna.Framework.Graphics.SpriteBatch sb)
        {
            if (!renderedOnce)
            {
                //Draw the incoming scene.
                GameContainer.Device.SetRenderTarget(InRT);
                In.Initialize();
                var ascene = In as AScene;
                if (ascene != null)
                    ascene.BaseUpdate(gameTime);
                else
                    In.Update(gameTime);
                In.Draw(gameTime, sb);

                //Draw the outgoing scene.
                GameContainer.Device.SetRenderTarget(OutRT);
                Out.Draw(gameTime, sb);

                //Set the render target to the screen
                GameContainer.Device.SetRenderTarget(null);

                renderedOnce = true;
            }

            GameContainer.Device.Clear(Color.Black);

            var dev = GameContainer.Device;

            dev.RasterizerState = RasterizerState.CullNone;

            dev.Textures[0] = OutRT;

            be.CurrentTechnique.Passes[0].Apply();

            //DrawOutgoing
            be.World = Matrix.CreateTranslation(new Vector3(-240, -400, 0)) * GetOutgoingMatrix(Percent);
            be.Texture = OutRT;
            be.Alpha = GetOutgoingTransparency(Percent);

            be.GraphicsDevice.DrawUserIndexedPrimitives(
                PrimitiveType.TriangleStrip,
                vertices,
                0,
                vertices.Length,
                indices,
                0,
                vertices.Length - 2
                );

            be.CurrentTechnique.Passes[0].Apply();

            //DrawIncoming
            be.World = Matrix.CreateTranslation(new Vector3(-240, -400, 0)) * GetIncommingMatrix(Percent);
            be.Texture = InRT;
            be.Alpha = GetIncommingTransparency(Percent);

            be.GraphicsDevice.DrawUserIndexedPrimitives(
                PrimitiveType.TriangleStrip,
                vertices,
                0,
                vertices.Length,
                indices,
                0,
                vertices.Length - 2
                );
        }

        protected virtual Matrix GetOutgoingMatrix(float percent)
        {
            return Matrix.CreateTranslation(new Vector3(240, 0, 0)) *
                Matrix.CreateRotationY(-1 * percent * (float)Math.PI / 2f) *
                Matrix.CreateTranslation(new Vector3(- 240, 0, 0));
        }

        protected virtual float GetIncommingTransparency(float percent)
        {
            return 1;
        }

        protected virtual Matrix GetIncommingMatrix(float percent)
        {
            return Matrix.CreateTranslation(new Vector3(480 - (percent * percent * 480f), 0, 0));
        }

        protected virtual float GetOutgoingTransparency(float percent)
        {
            return 1 - percent * percent;
        }
    }
}
